package com.ficus.road.maintain.controller.carmanager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ficus.road.maintain.core.model.CarDTO;
import com.ficus.road.maintain.core.model.carmanager.*;
import com.ficus.road.maintain.core.model.dingtalk.DingTalkUserInfo;
import com.ficus.road.maintain.service.CarService;
import com.ficus.road.maintain.service.carmanager.CarInfoService;
import com.ficus.road.maintain.service.carmanager.CarLogService;
import com.ficus.road.maintain.service.carmanager.CarManagerService;
import com.ficus.road.maintain.service.carmanager.CarStatusService;
import com.ficus.road.maintain.util.AliyunOSSUtil;
import com.ficus.road.maintain.util.MD5Util;
import com.ficus.road.maintain.util.dingtalk.DingTalkUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author xiawen yang
 * @date 2022/2/17 下午3:47
 */
@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/car_manager")
public class CarManagerController {

    private static final String PREFIX = "upload_data/";
    private static final String SUFFIX = ".jpg";
    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final String CAR_LOG_OP_BIND = "bind_car";
    private static final String CAR_LOG_OP_UNBIND = "unbind_car";
    private final CarManagerService carManagerService;
    private final CarStatusService carStatusService;
    private final CarInfoService carInfoService;
    private final CarLogService carLogService;
    private final CarService carService;
    private final AliyunOSSUtil aliyunOSSUtil;
    private final DingTalkUtil dingTalkUtil;
    private final ThreadPoolExecutor prometheusProcessorPool = new ThreadPoolExecutor(5, 10,
            0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(20), new CustomizableThreadFactory("prometheusProcessor-pool-"));
    @Value("${car_manager.bind_timeout}")
    private String bindTimeout;

    @PostMapping("/car_bind")
    public ResponseEntity<CarBindResponse> carBind(@RequestBody CarBindRequest carBindRequest) {
        // 打印日志
        try {
            log.info("调用/car_bind");
            log.info(objectMapper.writeValueAsString(carBindRequest));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        CarBindResponse carBindResponse;
        DingTalkUserInfo dingTalkUserInfo = null;
        try {
            dingTalkUserInfo = dingTalkUtil.getUserInfo(carBindRequest.getAuthCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (ObjectUtils.isEmpty(dingTalkUserInfo)) {
            log.error("查询不到当前钉钉用户");
            carBindResponse = CarBindResponse.builder().errorCode("400").message("查询不到当前用户").name("").carId(carBindRequest.getCarId()).licensePlateNumber("").build();
            return new ResponseEntity<>(carBindResponse, HttpStatus.BAD_REQUEST);
        }
        CarInfo carInfo = carInfoService.findByCarId(carBindRequest.getCarId());
        if (ObjectUtils.isEmpty(carInfo)) {
            log.error("CarBind Error, carId无效");
            carBindResponse = CarBindResponse.builder().errorCode("400").message("CarBind Error, carId无效").name("").carId(carBindRequest.getCarId()).licensePlateNumber("").build();
            return new ResponseEntity<>(carBindResponse, HttpStatus.BAD_REQUEST);
        }

        BindCarInput bindCarInput = carManagerService.convert2BindCarInput(carBindRequest, dingTalkUserInfo);
        // 日志
        CarLog carLog = CarLog.builder().timestamp(System.currentTimeMillis() * 1000000).operation(CAR_LOG_OP_BIND).bindCar(bindCarInput).build();
        carLogService.saveOrUpdate(carLog);
        // 最近12小时的carStatus是有效的
        long validTimestamp = System.currentTimeMillis() * 1000000 - TimeUnit.SECONDS.toNanos(Long.parseLong(bindTimeout));
        CarStatus carStatus = carStatusService.findBindCarStatusByCarId(bindCarInput.getCarId(), validTimestamp);
        // 如果找到了carStatus，且当前carId绑定的用户不是绑定请求中传入的userId，需要把当前carId的userId解绑
        if (ObjectUtils.isNotEmpty(carStatus) && StringUtils.isNotEmpty(carStatus.getUserid()) && !bindCarInput.getUserInfo().getUserId().equals(carStatus.getUserid())) {
            // 解绑userId(根据userid查出的carId为空)
            carStatusService.createCarStatus(carStatus.getUserid(), null, System.currentTimeMillis() * 1000000);
        }
        // 如果找到了userStatus, 且当前userId绑定的车辆不是请求中传入的carId, 需要把当前userId和carId解绑
        CarStatus userStatus = carStatusService.findBindCarStatusByUserId(bindCarInput.getUserInfo().getUserId(), validTimestamp);
        if (ObjectUtils.isNotEmpty(userStatus) && !bindCarInput.getCarId().equals(userStatus.getCarId())) {
            // 解绑carId
            carStatusService.createCarStatus(null, userStatus.getCarId(), System.currentTimeMillis() * 1000000);
        }
        // 绑定车辆
        carStatusService.createCarStatus(bindCarInput.getUserInfo().getUserId(), bindCarInput.getCarId(), System.currentTimeMillis() * 1000000);
        // 通知车辆（有bug, 这样车没上线的情况下也会给司机发送上线通知）
//        String preDefaultUserId = carInfo.getDefaultUserId();
//        if (StringUtils.isNotEmpty(carInfo.getDefaultUserId()) && !carInfo.getDefaultUserId().equals(dingTalkUserInfo.getUserId())) {
//            String text = String.format("# 车辆上线通知\n- 车牌：%s\n- 时间：%s\n",
//                    carInfo.getLicensePlateNumber(),
//                    MyDateUtil.dateFormatStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
//            DingTalkOpenMessage message = DingTalkOpenMessage
//                    .builder()
//                    .msgType("markdown")
//                    .markDown(MarDownMessage.builder().title("车辆上线通知").text(text).build()).build();
//            try {
//                dingTalkUtil.corpMessageAsyncSend(Arrays.asList(dingTalkUserInfo.getUserId()), null, Boolean.FALSE, message);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//        // 修改车辆的default_user_id
//        carInfoService.modifyCarInfoByDefaultUserId(carInfo.getCarId(), dingTalkUserInfo.getUserId());

        // 修改138后端的车辆信息
        carService.updateCar(bindCarInput.getCarId(), CarDTO.builder().driver(bindCarInput.getUserInfo().getName()).build());

        carBindResponse = CarBindResponse.builder().errorCode("0").message("succ").name(dingTalkUserInfo.getName()).licensePlateNumber(carInfo.getLicensePlateNumber()).build();
        return new ResponseEntity<>(carBindResponse, HttpStatus.OK);
    }

    @PostMapping("/car_unbind")
    public ResponseEntity<CarUnbindResponse> carUnbind(@RequestBody CarUnbindRequest carUnbindRequest) {
        // 打印日志
        try {
            log.info("调用/car_unbind");
            log.info(objectMapper.writeValueAsString(carUnbindRequest));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        CarUnbindResponse carUnbindResponse;
        DingTalkUserInfo dingTalkUserInfo = null;
        try {
            dingTalkUserInfo = dingTalkUtil.getUserInfo(carUnbindRequest.getAuthCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 测试
//        dingTalkUserInfo = DingTalkUserInfo.builder().userId("226344426538097494").build();
        if (ObjectUtils.isEmpty(carUnbindRequest)) {
            log.error("查询不到当前钉钉用户");
            carUnbindResponse = CarUnbindResponse.builder().errorCode("400").message("查询不到当前用户").name("").build();
            return new ResponseEntity<>(carUnbindResponse, HttpStatus.BAD_REQUEST);
        }

        UnbindCarInput unbindCarInput = carManagerService.convert2UnbindCarInput(carUnbindRequest, dingTalkUserInfo);
        // 日志
        CarLog carLog = CarLog.builder().timestamp(System.currentTimeMillis() * 1000000).operation(CAR_LOG_OP_UNBIND).unbindCarInput(unbindCarInput).build();
        carLogService.saveOrUpdate(carLog);
        long validTimestamp = System.currentTimeMillis() * 1000000 - TimeUnit.SECONDS.toNanos(Long.parseLong(bindTimeout));
        CarStatus userStatus = carStatusService.findBindCarStatusByUserId(unbindCarInput.getUserInfo().getUserId(), validTimestamp);
        // 判断是否找到了用户的有效绑定记录
        CarStatus status = carStatusService.queryBindCarByUserId(unbindCarInput.getUserInfo().getUserId());
        if (ObjectUtils.isNotEmpty(status)) {
            // 解绑userId
            log.info("解绑userId");
            carStatusService.createCarStatus(unbindCarInput.getUserInfo().getUserId(), null, System.currentTimeMillis() * 1000000);
            // 解绑carId
            log.info("解绑carId");
            carStatusService.createCarStatus(null, status.getCarId(), System.currentTimeMillis() * 1000000);
            // 解绑后清除上下线记录
            log.info("清除上下线记录");
            carManagerService.clearCarRecord(status.getCarId());
        }
        carUnbindResponse = CarUnbindResponse.builder().errorCode("0").message("succ").name(dingTalkUserInfo.getName()).build();
        return new ResponseEntity<>(carUnbindResponse, HttpStatus.OK);
    }

    @PostMapping("/car_bind_query")
    public ResponseEntity<CarBindQueryResponse> carBindQuery(@RequestBody CarBindQueryRequest carBindQueryRequest) {
        // 打印日志
        try {
            log.info("调用/car_bind_query");
            log.info(objectMapper.writeValueAsString(carBindQueryRequest));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        CarBindQueryResponse carBindQueryResponse;
        long validTimestamp = System.currentTimeMillis() * 1000000 - TimeUnit.SECONDS.toNanos(Long.parseLong(bindTimeout));
        DingTalkUserInfo dingTalkUserInfo = new DingTalkUserInfo();
        String userId = carBindQueryRequest.getUserId();
        if (StringUtils.isEmpty(carBindQueryRequest.getUserId())) {
            try {
                dingTalkUserInfo = dingTalkUtil.getUserInfo(carBindQueryRequest.getAuthCode());
                userId = dingTalkUserInfo.getUserId();
            } catch (Exception e) {
                log.error(e.getMessage());
                carBindQueryResponse = CarBindQueryResponse.builder().errCode(-1).message("error").build();
                return new ResponseEntity<>(carBindQueryResponse, HttpStatus.BAD_REQUEST);
            }
            if (ObjectUtils.isEmpty(dingTalkUserInfo)) {
                log.error("查询不到当前钉钉用户");
                carBindQueryResponse = CarBindQueryResponse.builder().errCode(-1).message("error").build();
                return new ResponseEntity<>(carBindQueryResponse, HttpStatus.BAD_REQUEST);
            }
        }

        CarStatus status = carStatusService.queryBindCarByUserId(userId);
        if (ObjectUtils.isNotEmpty(status)) {
            // 查询车辆信息
            CarInfo carInfo = carInfoService.findByCarId(status.getCarId());
            carBindQueryResponse = CarBindQueryResponse.builder().errCode(0).message("succ").isBind(true).carId(status.getCarId())
                    .licensePlateNumber(carInfo.getLicensePlateNumber()).userId(carBindQueryRequest.getUserId()).name(dingTalkUserInfo.getName()).build();
        } else {
            carBindQueryResponse = CarBindQueryResponse.builder().errCode(0).message("succ").isBind(false)
                    .userId(carBindQueryRequest.getUserId()).name(dingTalkUserInfo.getName()).build();
        }
        return new ResponseEntity<>(carBindQueryResponse, HttpStatus.OK);
    }

    @PostMapping("/car_info_query")
    public ResponseEntity<CarInfoQueryResponse> carInfoQuery(@RequestBody CarInfoQueryRequest carInfoQueryRequest) {
        // 打印日志
        try {
            log.info("调用/car_info_query");
            log.info(objectMapper.writeValueAsString(carInfoQueryRequest));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        CarInfoQueryResponse carInfoQueryResponse;
        CarInfo carInfo = carInfoService.findByCarId(carInfoQueryRequest.getCarId());
        if (ObjectUtils.isEmpty(carInfo)) {
            carInfoQueryResponse = CarInfoQueryResponse.builder().errCode(400).message("CarInfoQuery Error, carId无效").carInfo(carInfo).build();
        }
        carInfoQueryResponse = CarInfoQueryResponse.builder().errCode(0).message("succ").carInfo(carInfo).build();
        return new ResponseEntity<>(carInfoQueryResponse, HttpStatus.OK);
    }


    @PostMapping("/upload_file")
    public ResponseEntity<UploadFileResponse> uploadFile(HttpServletRequest httpServletRequest) {
        log.info("调用/upload_file");
        StandardMultipartHttpServletRequest request = (StandardMultipartHttpServletRequest) httpServletRequest;
//        Iterator<String> iterator = request.getFileNames();
//        while ((iterator.hasNext())) {
//            MultipartFile file = request.getFile(iterator.next());
//            try {
//                byte[] data = file.getBytes();
//                String md5String = MD5Util.getMD5String(data);
//                log.info(md5String);
//                String fileName = String.format("%s%s_%d%s", PREFIX, md5String, System.nanoTime(), SUFFIX);
//                aliyunOSSUtil.uploadImgByFileName(fileName, data);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
        MultipartFile file = request.getFile("file");
        byte[] data = new byte[0];
        try {
            data = file.getBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String md5String = MD5Util.getMD5String(data);
        log.info(md5String);
        String fileName = String.format("%s%s_%d%s", PREFIX, md5String, System.currentTimeMillis() * 1000000, SUFFIX);
        aliyunOSSUtil.uploadImgByFileName(fileName, data);
        UploadFileResponse uploadFileResponse = UploadFileResponse.builder()
                .key(fileName)
                .errCode(0)
                .message("succ")
                .build();
        return new ResponseEntity<>(uploadFileResponse, HttpStatus.OK);
    }

    @PostMapping("/prometheus_alert")
    public ResponseEntity<PrometheusAlertResponse> receivePrometheusAlerts(@RequestBody WebhookMessage webhookMessage) {
        // todo (绑定, 上线) -> (从绑定中获取绑定结果，然后)通知
        // todo 线程池的异常处理机制
        prometheusProcessorPool.execute(() -> carManagerService.processPrometheusAlerts(webhookMessage));
        PrometheusAlertResponse prometheusAlertResponse = PrometheusAlertResponse.builder().errCode(0).message("succ").build();
        return new ResponseEntity<>(prometheusAlertResponse, HttpStatus.OK);
    }

    @PostMapping("/testCarUp")
    public ResponseEntity<String> testCarUp(@RequestBody Map<String, String> labels) {
        carManagerService.processCarUp(labels);
        return new ResponseEntity<>("success", HttpStatus.OK);
    }

    @PostMapping("/testCarDown")
    public ResponseEntity<String> testCarDown(@RequestBody Map<String, String> labels) {
        carManagerService.processCarDown(labels);
        return new ResponseEntity<>("success", HttpStatus.OK);
    }
}
